﻿/**************************************************************************
**
** This file is part of QSsh
**
** Copyright (c) 2012 LVK
**
** Contact: andres.pagliano@lvklabs.com
**
** GNU Lesser General Public License Usage
**
** This file may be used under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation and
** appearing in the file LICENSE.LGPL included in the packaging of this file.
** Please review the following information to ensure the GNU Lesser General
** Public License version 2.1 requirements will be met:
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
**************************************************************************/

#include "securefileuploader.h"

#include <QtDebug>
#include <QFileInfo>

SecureFileUploader::SecureFileUploader(QObject *parent) :
    QObject(parent), m_connection(0)
{

}

SecureFileUploader::~SecureFileUploader(){
    if(m_connection != NULL){
        m_connection->closeAllChannels();
    }
    delete m_connection;
}

void SecureFileUploader::upload(const QString &localFile, const QString &dest)
{
    if(m_connection != NULL){
        if(m_connection->state() != QSsh::SshConnection::Connected){
            qDebug() << "Ssh is disconnected";
            emit sendsshres(SSH_SOCKETERRO);
            return;
        }
        QFileInfo info(localFile);
        m_localFilename = info.canonicalFilePath();
        m_remoteFilename = dest + "/" + info.fileName();
        m_channel = m_connection->createSftpChannel();

        if (m_channel) {
            disconnect(m_channel.data(), SIGNAL(initialized()),this,
                    SLOT(onChannelInitialized()));
            disconnect(m_channel.data(), SIGNAL(initializationFailed(QString)),this,
                    SLOT(onChannelError(QString)));
            disconnect(m_channel.data(), SIGNAL(finished(QSsh::SftpJobId, QString)),this,
                    SLOT(onOpfinished(QSsh::SftpJobId, QString)));
            connect(m_channel.data(), SIGNAL(initialized()),this,
                    SLOT(onChannelInitialized()));
            connect(m_channel.data(), SIGNAL(initializationFailed(QString)),this,
                    SLOT(onChannelError(QString)));
            connect(m_channel.data(), SIGNAL(finished(QSsh::SftpJobId, QString)),this,
                    SLOT(onOpfinished(QSsh::SftpJobId, QString)));

            m_channel->initialize();

        } else {
            emit sendsshres(SSH_SFTPERRO);
            qDebug() << "SecureUploader: Error null channel";
        }
    }else{
        emit sendsshres(SSH_SOCKETERRO);
        qDebug() << "SecureUploader: Error null connection";
    }

}

void SecureFileUploader::onConnected()
{
    qDebug() << "SecureUploader: Connected";
    qDebug() << "SecureUploader: Creating SFTP channel...";
    emit sendsshres(SSH_CONNECTED);
//    if(shell->isOpen()){
//        shell->close();
//        qDebug() << "shell close";
//    }
    shell = m_connection->createRemoteShell();
    disconnect(shell.data(), SIGNAL(readyReadStandardOutput()),this, SLOT(dataReceived()));
    connect(shell.data(), SIGNAL(readyReadStandardOutput()),this, SLOT(dataReceived()));
    shell.data()->start();
}

void SecureFileUploader::onDisConnected(){
    disconnect(m_connection, SIGNAL(connected()), this, SLOT(onConnected()));
    disconnect(m_connection, SIGNAL(error(QSsh::SshError)), this, SLOT(onConnectionError(QSsh::SshError)));
    disconnect(m_connection, SIGNAL(disconnected()), this, SLOT(onDisConnected()));
    delete m_connection;
    qDebug() << "SecureUploader: DisConnectied";
}

void SecureFileUploader::onConnectionError(QSsh::SshError err)
{
    disconnect(m_connection, SIGNAL(connected()), this, SLOT(onConnected()));
    disconnect(m_connection, SIGNAL(error(QSsh::SshError)), this, SLOT(onConnectionError(QSsh::SshError)));
    disconnect(m_connection, SIGNAL(disconnected()), this, SLOT(onDisConnected()));
    delete m_connection;
    switch(err)
    {
    case QSsh::SshNoError:
        qDebug() << "sshConnectError SshNoError";
        emit sendsshmsg("sshConnectError SshNoError");
        break;
    case QSsh::SshSocketError:
        qDebug() << "sshConnectError SshSocketError";     // 拔掉网线是这种错误
        emit sendsshmsg("sshConnectError SshSocketError");
        break;
    case QSsh::SshTimeoutError:
        qDebug() << "sshConnectError SshTimeoutError";
        emit sendsshmsg("sshConnectError SshTimeoutError");
        break;
    case QSsh::SshProtocolError:
        qDebug() << "sshConnectError SshProtocolError";
        emit sendsshmsg("sshConnectError SshProtocolError");
        break;
    case QSsh::SshHostKeyError:
        qDebug() << "sshConnectError SshHostKeyError";
        emit sendsshmsg("sshConnectError SshHostKeyError");
        break;
    case QSsh::SshKeyFileError:
        qDebug() << "sshConnectError SshKeyFileError";
        emit sendsshmsg("sshConnectError SshKeyFileError");
        break;
    case QSsh::SshAuthenticationError:
        qDebug() << "sshConnectError SshAuthenticationError";
        emit sendsshmsg("sshConnectError SshAuthenticationError");
        break;
    case QSsh::SshClosedByServerError:
        qDebug() << "sshConnectError SshClosedByServerError";
        emit sendsshmsg("sshConnectError SshClosedByServerError");
        break;
    case QSsh::SshInternalError:
        qDebug() << "sshConnectError SshInternalError";
        emit sendsshmsg("sshConnectError SshInternalError");
        break;
    default:
        break;
    }
}

void SecureFileUploader::onChannelInitialized()
{
    qDebug() << "SecureUploader: Channel Initialized";

    // TODO Choose the overwrite mode: SftpOverwriteExisting, SftpAppendToExisting, SftpSkipExisting
    QSsh::SftpJobId job = m_channel->uploadFile(m_localFilename, m_remoteFilename,
                                                QSsh::SftpOverwriteExisting);

    if (job != QSsh::SftpInvalidJob) {
        qDebug() << "SecureUploader: Starting job #" << job;
        emit sendsshres(SSH_FILESTART);
    } else {
        qDebug() << "SecureUploader: Invalid Job";
        emit sendsshres(SSH_FILEERRO);
    }
}

void SecureFileUploader::onChannelError(const QString &err)
{
    qDebug() << "SecureUploader: Error: " << err;
    emit sendsshres(SSH_FILEERRO);
    emit sendsshmsg(err);
}

void SecureFileUploader::onOpfinished(QSsh::SftpJobId job, const QString &err)
{
    qDebug() << "SecureUploader: Finished job #" << job << ":" << (err.isEmpty() ? "OK" : err);
    emit sendsshres(SSH_FILEEND);
}

void SecureFileUploader::SSHconnect(QString host,int port,QString username,QString passward){
    QSsh::SshConnectionParameters params;
    params.setHost(host);
    params.setUserName(username);
    params.setPassword(passward);
    params.authenticationType = QSsh::SshConnectionParameters::AuthenticationTypePassword;
    //argParameters.authenticationType = QSsh::SshConnectionParameters::AuthenticationTypePassword;
    params.timeout = 15;
    params.setPort(port);
    m_connection = new QSsh::SshConnection(params, this); // TODO free this pointer!
    connect(m_connection, SIGNAL(connected()),this, SLOT(onConnected()));
    connect(m_connection, SIGNAL(error(QSsh::SshError)),this, SLOT(onConnectionError(QSsh::SshError)));
    connect(m_connection, SIGNAL(disconnected()), this, SLOT(onDisConnected()));
    qDebug() << "SecureUploader: Connecting to host" << host;
    m_connection->connectToHost();
}

void SecureFileUploader::SSHdisconnect(){
    if(m_connection != NULL){
        if(m_connection->state() == QSsh::SshConnection::Connected || m_connection->state() == QSsh::SshConnection::Connecting){
            qDebug() << "Ssh is already connected";
            emit sendsshres(SSH_DISCONN);
            m_connection->disconnectFromHost();
        }
    }
}

void SecureFileUploader::Slot_sendSSHcmd(QString cmdstr){
    if(m_connection != NULL){
        cmdstr += "\n";
        if(shell->write(cmdstr.toLatin1().data()) > 0)
            emit sendsshres(SSH_SENDCMD);
    }else{
        emit sendsshres(SSH_SOCKETERRO);
    }

}

void SecureFileUploader::dataReceived(){
    QByteArray byteRecv = shell->readAllStandardOutput();
    QString strRecv = QString::fromUtf8(byteRecv);

//    if(strRecv.contains("password") || strRecv.contains(QString::fromLocal8Bit("密码")))
//    {
//        QString pwd = "root\n";
//        shell->write(pwd.toUtf8().data());
//    }

//    if(strRecv.contains("yes/no/[fingerprint]"))
//    {
//        QString str = "yes\n";
//        shell->write(str.toUtf8().data());
//    }

    if(!strRecv.isEmpty()) //过滤空行
    {
        strRecv = strRecv.trimmed();
        emit sendsshmsg(strRecv);
    }
}
